package com.motorola.dp.jenkinsmonitor.service.util.http;

import java.io.IOException;
import java.io.InputStream;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.auth.AuthenticationException;
import org.apache.http.auth.Credentials;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.params.ConnRoutePNames;
import org.apache.http.impl.auth.BasicScheme;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import com.motorola.dp.jenkinsmonitor.model.util.HttpRequestParameters;
import com.motorola.dp.jenkinsmonitor.model.util.ResponseInputStream;
import com.motorola.dp.jenkinsmonitor.service.util.properties.PropertiesService;

@Service("httpService")
public class DefaultHttpService implements HttpService {

    @Value("#{new org.apache.http.impl.client.DefaultHttpClient()}")
    private HttpClient httpClient;
    @Value("#{applicationPropertiesService}")
    private PropertiesService propertiesService;

    @PostConstruct
    public void afterPropertiesSet() throws Exception {
        Boolean useProxy = propertiesService.getBoolean("proxy.useProxy");
        if (useProxy) {
            initializeProxy();
        }
    }

    private void initializeProxy() {
        String proxyHost = propertiesService.getString("proxy.host");
        Integer proxyPort = propertiesService.getInteger("proxy.port");

        HttpHost proxy = new HttpHost(proxyHost, proxyPort, "http");
        httpClient.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, proxy);
    }

    public ResponseInputStream fetchStream(HttpRequestParameters parameters) throws IOException {
        HttpGet httpGet = new HttpGet(parameters.getUrl());
        if (authenticationParamsSpecified(parameters)) {
            provideAuthentication(httpGet, parameters);
        }
        return requestStream(httpGet);
    }

    private boolean authenticationParamsSpecified(HttpRequestParameters parameters) {
        return parameters.getUsername() != null && parameters.getPassword() != null;
    }

    private void provideAuthentication(HttpGet httpGet, HttpRequestParameters parameters)
            throws IOException {
        String username = parameters.getUsername();
        String password = parameters.getPassword();
        Credentials credentials = new UsernamePasswordCredentials(username, password);
        try {
            httpGet.addHeader(new BasicScheme().authenticate(credentials, httpGet));
        } catch (AuthenticationException e) {
            throw new IOException(e);
        }
    }

    private ResponseInputStream requestStream(HttpGet httpGet) throws IOException {
        HttpResponse response = httpClient.execute(httpGet);
        HttpEntity entity = response.getEntity();

        if (entity != null) {
            String contentType = entity.getContentType().getValue();
            InputStream is = entity.getContent();
            return new ResponseInputStream(is, contentType);
        }
        return null;
    }

    @PreDestroy
    public void releaseResources() {
        httpClient.getConnectionManager().shutdown();
    }

    public void setHttpClient(HttpClient httpClient) {
        this.httpClient = httpClient;
    }

    public void setPropsReader(PropertiesService propsReader) {
        this.propertiesService = propsReader;
    }
}
